/*
	FileName : bsp_IWWDG.c
	Descriptio :
	
	Created on 2014.03.31 by ZZP.
	
	Revision History:
	
*/

/* Includes ------------------------------------------------------------------*/
#include "stm32f2xx.h"
#include "ucos_ii.h"
#include "bsp.h"
#include <stdio.h>

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
__IO uint32_t LsiFreq = 0;
__IO uint32_t CaptureNumber = 0, PeriodValue = 0;
uint16_t tmpCC4[2] = {0, 0};

/* Private function prototypes -----------------------------------------------*/
uint32_t GetLSIFrequency(void);
void BSP_TIM5_ISRHandler(void);

////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
void BSP_IWDG_Init(void)
{
	/* Check if the system has resumed from IWDG reset */
	if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET)
	{
		/* Clear reset flags */
		RCC_ClearFlag();
	}
	else
	{
		/* IWDGRST flag is not set */
	}
 
	/* Get the LSI frequency:  TIM5 is used to measure the LSI frequency */
	LsiFreq = GetLSIFrequency();
   
	/* IWDG timeout equal to 2500ms (the timeout may varies due to LSI frequency
		dispersion) */
	/* Enable write access to IWDG_PR and IWDG_RLR registers */
	IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);

	/* IWDG counter clock: LSI/32 */
	IWDG_SetPrescaler(IWDG_Prescaler_32);

	/* Set counter reload value to obtain 1000ms IWDG TimeOut.
		Counter Reload Value = 1000ms/IWDG counter clock period
                          = 1000ms / (LSI/32)
                          = 1.0s / (LsiFreq/32)
                          = LsiFreq/(32 * 1)
                          = LsiFreq/32
   */
	IWDG_SetReload(LsiFreq/32);

	/* Reload IWDG counter */
	IWDG_ReloadCounter();

	/* Enable IWDG (the LSI oscillator will be enabled by hardware) */
	IWDG_Enable();
}

/**
  * @brief  Configures TIM5 to measure the LSI oscillator frequency. 
  * @param  None
  * @retval LSI Frequency
  */
uint32_t GetLSIFrequency(void)
{
	TIM_ICInitTypeDef  TIM_ICInitStructure;
	RCC_ClocksTypeDef  RCC_ClockFreq;

	/* Enable the LSI oscillator ************************************************/
	RCC_LSICmd(ENABLE);
  
	/* Wait till LSI is ready */
	while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
	{}

	/* TIM5 configuration *******************************************************/ 
	/* Enable TIM5 clock */
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
  
	/* Connect internally the TIM5_CH4 Input Capture to the LSI clock output */
	TIM_RemapConfig(TIM5, TIM5_LSI);

	/* Configure TIM5 presclaer */
	TIM_PrescalerConfig(TIM5, 0, TIM_PSCReloadMode_Immediate);
  
	/* TIM5 configuration: Input Capture mode ---------------------
		The LSI oscillator is connected to TIM5 CH4
		The Rising edge is used as active edge,
		The TIM5 CCR4 is used to compute the frequency value 
	------------------------------------------------------------ */
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_4;
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV8;
	TIM_ICInitStructure.TIM_ICFilter = 0;
	TIM_ICInit(TIM5, &TIM_ICInitStructure);
  
	/* Enable TIM5 counter */
	TIM_Cmd(TIM5, ENABLE);
  
	BSP_IntVectSet(BSP_INT_ID_TIM5, BSP_TIM5_ISRHandler);
    BSP_IntEn(BSP_INT_ID_TIM5);
	
	/* Reset the flags */
	TIM5->SR = 0;
    
	/* Enable the CC4 Interrupt Request */  
	TIM_ITConfig(TIM5, TIM_IT_CC4, ENABLE);


	/* Wait until the TIM5 get 2 LSI edges (refer to TIM5_IRQHandler() in 
		stm32f2xx_it.c file) ******************************************************/
	while(CaptureNumber != 2)
	{}
  
	/* Deinitialize the TIM5 peripheral registers to their default reset values */
	TIM_DeInit(TIM5);
	BSP_IntDis(BSP_INT_ID_TIM5);


	/* Compute the LSI frequency, depending on TIM5 input clock frequency (PCLK1)*/
	/* Get SYSCLK, HCLK and PCLKx frequency */
	RCC_GetClocksFreq(&RCC_ClockFreq);

	/* Get PCLK1 prescaler */
	if ((RCC->CFGR & RCC_CFGR_PPRE1) == 0)
	{ 
		/* PCLK1 prescaler equal to 1 => TIMCLK = PCLK1 */
		return ((RCC_ClockFreq.PCLK1_Frequency / PeriodValue) * 8);
	}
	else
	{ /* PCLK1 prescaler different from 1 => TIMCLK = 2 * PCLK1 */
		return (((2 * RCC_ClockFreq.PCLK1_Frequency) / PeriodValue) * 8) ;
	}
}


void BSP_TIM5_ISRHandler(void)
{
	if (TIM_GetITStatus(TIM5, TIM_IT_CC4) != RESET){    
		/* Get the Input Capture value */
		tmpCC4[CaptureNumber++] = TIM_GetCapture4(TIM5);
   
		/* Clear CC4 Interrupt pending bit */
		TIM_ClearITPendingBit(TIM5, TIM_IT_CC4);

		if (CaptureNumber >= 2){
			/* Compute the period length */
			PeriodValue = (uint16_t)(0xFFFF - tmpCC4[0] + tmpCC4[1] + 1);
		}
	}
}


/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
